﻿/// Copyright © 2013 Microsoft Corporation. 
/// This project is released under the Microsoft Public License (MS-PL)
///
namespace DataMorph.Processing
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Script.Serialization;

    using DataMorph.Common;
    using DataMorph.Common.Contracts;
    using DataMorph.Common.Storage;

    using Microsoft.Practices.Unity;
    using Microsoft.WindowsAzure.Storage;
    using Microsoft.WindowsAzure.Storage.Queue;

    public class WorkQueue : IWorkQueue
    {
        private readonly CloudQueueClient queueClient;

        private readonly CloudQueue queueReference;

        private readonly OperationContext operationContext;

        private readonly QueueRequestOptions queueRequestOptions;

        [InjectionConstructor]
        public WorkQueue(ICloudStorageAccount cloudStorageAccount) : this(cloudStorageAccount, 32)
        {
        }

        public WorkQueue(ICloudStorageAccount cloudStorageAccount, int workBatchSize)
        {
            this.WorkBatchSize = workBatchSize > 32 ? 32 : workBatchSize;

            this.queueClient = cloudStorageAccount.CreateCloudQueueClient();
            this.queueReference = this.queueClient.GetQueueReference(Settings.WorkQueueName);
            this.queueReference.CreateIfNotExists();

            this.operationContext = new OperationContext();
            this.queueRequestOptions = new QueueRequestOptions
            {
                MaximumExecutionTime = TimeSpan.FromMinutes(3),
                RetryPolicy = DataMorphGlobalRetryPolicy.NewPolicy
            };

            this.queueReference.CreateIfNotExists(this.queueRequestOptions, this.operationContext);
        }

        public int WorkBatchSize { get; private set; }

        public void AddWorkRequests(IEnumerable<ProcessingWorkRequest> workRequests)
        {
            var jsonSerializer = new JavaScriptSerializer();
            var queueMessages = workRequests.Select(req => new CloudQueueMessage(jsonSerializer.Serialize(req))).ToList();
            foreach (var cloudQueueMessage in queueMessages)
            {
                this.queueReference.AddMessage(cloudQueueMessage);
            }
        }

        public void DeleteWorkRequest(ProcessingWorkRequest workRequest)
        {
            this.queueReference.DeleteMessage(workRequest.GetMessageReference());
        }

        public IEnumerable<ProcessingWorkRequest> GetWorkRequests()
        {
            var messages = this.queueReference.GetMessages(
                                                this.WorkBatchSize, 
                                                TimeSpan.FromMinutes(40), 
                                                this.queueRequestOptions, 
                                                this.operationContext);

            var workRequestsList = new List<ProcessingWorkRequest>();
            var jsonSerializer = new JavaScriptSerializer();
            foreach (var cloudQueueMessage in messages)
            {
                var workRequest = jsonSerializer.Deserialize<ProcessingWorkRequest>(cloudQueueMessage.AsString);
                workRequest.SetMessageReference(cloudQueueMessage);
                workRequest.SetQueueReference(this);
                workRequestsList.Add(workRequest);
            }

            return workRequestsList;
        }
    }
}